"""Modulo que permite resolver problemas de ajedrez"""

from pieces import *
from games import *
from math import sqrt
import copy

class State():
	"""Clase que representa a un estado del juego"""
	def __init__(self,pieces,kingPos):
		"pieces: lista de piezas disponibles para cada jugador"
		"king: posicion del Rey a atrapar (fila,columna)"		
		"player: 0=blancas;1=negras"
		"utility: 1 para cuando encuentra la solucion"
		"board: tablero"
		self.board=[[('0')] * 8 for i in range(8)]
		self.player=0
		self.utility=False
		self.king=kingPos
		self.pieces=[]		
		aux1=[]
		aux2=[]	
		"Acomoda las piezas en el tablero"
		for p in pieces[0]:
			self.board[p.position[0]][p.position[1]]=p.name
			aux1.append(copy.copy(p))
		
		self.pieces.append(aux1)
		
		
		for p in pieces[1]:
			self.board[p.position[0]][p.position[1]]=p.name
			aux2.append(copy.copy(p))
		
		self.pieces.append(aux2)
	
	def printBoard(self):
		"Muestra el tablero en consola"		
		for x in range(8):
			for y in range(8):			
				print self.board[7-x][y] + '  ' , 		
			print '\n'


class ChessProblem(Game):
	"""	
	Resuelve problemas de ajedrez del tipo Directmates.
	Recibe las piezas disponibles para cada jugador, a quien corresponde jugar
	y el objetivo a lograr.
	"""	
	def __init__(self, pieces, king):
		self.initial = State(pieces,king)

	def inBoard(self,cell):
		if((cell[0] > 7) or (cell[0] < 0) or (cell[1] > 7) or (cell[1] < 0) ):
				return False
		return True

	def actions(self, state):
		
		"""Devuelve la lista de movimientos disponibles para cada pieza de la lista
		pieces"""
		moves=[] #[ (posicionActual, posicionDestino),... ]
		
		#Guarda las posiciones de las piezas del jugador
		playerPieces=[] 
		for p in state.pieces[state.player]:
			playerPieces.append(p.position)
		
		#Guardo las posiciones del oponente
		oponentPieces=[]
		for p in state.pieces[1+(-1*state.player)]:
			oponentPieces.append(p.position)

		"Recorro las piezas del jugador actual"		
		for p in state.pieces[state.player]:
			
			blockedTrayectory=[] #Guarda las celdas que estan bloqueadas
					
			"Recorro los movientos de cada pieza"
			for futureCell in p.posible_cells():
									
				#Calcula el movimiento realizado
				f=list(futureCell)
				pos=list(p.position)
				m=[ f[0]-pos[0],f[0]-pos[1] ]
				
				#Chequea que no sea una trayecetoria bloqueada
				if(futureCell in blockedTrayectory):
					continue
		
				#Chequeo que la posicion no este ya ocupada por una pieza del mismo jugador			
				if(futureCell in playerPieces):
					"""Asegura que los movimientos en la misma direccion no sean permitidos.
					El caballo es la unica excepcion"""
					if(p.name!='N'):
						direction=[]
											
						if(m[0]==0):
							direction.append(m[0])
						else:
							direction.append(m[0]/int(sqrt(m[0]**2)))
						if(m[1]==0):
							direction.append(m[1])
						else:
							direction.append(m[1]/int(sqrt(m[1]**2)))
						

						while(self.inBoard(futureCell)):
							futureCell=list(futureCell)
							futureCell[0]+=direction[0]		
							futureCell[1]+=direction[1]	
							futureCell=tuple(futureCell)							
							blockedTrayectory.append(futureCell)					
					
					continue							
				
				if(p.name=='P'):
					#Movimientos particulares de peon	
					if( ((state.player==0) and (m[0]<0)) or ((state.player==1) and (m[0]>0))) :
						continue 

					"""Debo chequear que no este obstruido por el contrincante. Solo si 
					no se ataca"""
					if(0 in m):#si se mueve hacia una direccion 
							if (futureCell in oponentPieces):
								continue
							if( (2 in m) or (-2 in m)):
								"""En caso que avance 2. Debe estar en la primer fila. Y
								la casilla de en medio tambien debe estar libre"""
								if(p.position[0]!=1+(5*state.player)):
									continue
								if( (futureCell[0]-(-1)**state.player ,futureCell[1]) in (oponentPieces or playerPieces)):
									continue
	
				
					else:
						if(futureCell not in oponentPieces):#Por ahora solo avanza en diagonal si ataca (Ver captura al paso)
							continue
				
				if(p.name=='K'):
					"""Debo chequear que el rey no se mueva a una celda amenzada"""
					amenazada=False
					for p in state.pieces[state.player]:
						for m in p.moves:
							if(self.amenaza(p.position,list(m),playerPieces,oponentPieces,futureCell)):
								amenazada=True
								break
					if(amenazada):	
						continue
				
				
				
				
				
				#Ninguna pieza puede 'comer' al rey
				if(futureCell==state.king):
					continue
				
				moves.append((p.position,futureCell))	
		
	
		return moves
		
		
	def jaque(self,state):
			"""Chequea si alguna pieza del jugador actual amenaza al rey"""
			jaque=False
			
			playerPieces=[] 
			for p in state.pieces[state.player]:
				playerPieces.append(p.position)
		
			oponentPieces=[]
			for p in state.pieces[1+(-1*state.player)]:
				oponentPieces.append(p.position)
				
			
			for p in state.pieces[state.player]:
				
				#Preguntar por caballo, peon y rey propio
				if(p.name=='N'):
					continue
				
				if(p.name=='P'):
					continue
				
				if(p.name=='K'):
					continue
				
				if(p.name!='R'):
					#Pruebo diagonales. Para reina y alfil
					direction=[[1,1],[1,-1],[-1,1],[-1,-1]]
					i=0
					while(jaque!=True and i<4):
						jaque=self.amenaza(p.position, direction[i],playerPieces,oponentPieces,state.king)
						i+=1
			
				if jaque:
					return jaque
			
				if(p.name!='B'):
					#Pruebo verticales y horizontales. Para reina y torre
					direction=[[0,1],[0,-1],[1,0],[-1,0]]
					i=0
					while(jaque!=True and i<4):
						jaque=self.amenaza(p.position, direction[i],playerPieces,oponentPieces,state.king)
						i+=1	

				if jaque:
					return jaque
		
			return jaque

		
	def amenaza(self,cell,direction,playerPieces,oponentPieces,kingPos):
		"""Indica si la pieza ubicada en cell amenza al rey ubicado en kingPos
		en la direccion dada"""
		auxCell=list(cell)
		auxCell[0]+=direction[0]
		auxCell[1]+=direction[1]
		while(self.inBoard(tuple(auxCell))):
			if(tuple(auxCell) not in playerPieces):
				if(tuple(auxCell) in oponentPieces):
					if(tuple(auxCell)==kingPos):
						return True
					else:
						return False
			else:
				return False
			auxCell[0]+=direction[0]
			auxCell[1]+=direction[1]
		
		return False
	
	def result(self, state,move):
		"Return the state that results from making a move from a state."
		newState=State(state.pieces,state.king)
		newState.player=state.player
		
		"Cambio el tablero"		
		newState.board[move[0][0]][move[0][1]]='0' #Limpia la poscion
		
		if(newState.board[move[1][0]][move[1][1]]!='0'):
			"Significa que hay una pieza enemiga. Hay que eliminarla"
			for p in newState.pieces[1+(-1*newState.player)]:
				if p.position==move[1]:
					newState.pieces[1+(-1*newState.player)].remove(p)			
			
		"Cambio la poscion de la pieza que se mueve"	
		for p in newState.pieces[newState.player]:
			if (p.position==move[0]):
				p.position=move[1]
				newState.board[move[1][0]][move[1][1]]=p.name
						
				
				"Si se mueve el rey objetivo, actualizo la pos para el estado"
				if(newState.player==1 and p.name=='K'):
					newState.king=move[1]
		
		
		newState.utility=self.compute_utility(newState)
		
		newState.player=1+(-1*newState.player)
		
		return newState
			
	def utility(self, state, player):
		"Return the value of this final state to player."
		return not state.utility

		
	def compute_utility(self,state):
		return self.jaque(state)

	def terminal_test(self, state):
		"Return True if this is a final state for the game."
		return state.utility
		
	def to_move(self, state):
		"Return the player whose move it is in this state."
		return state.player
	
	
	def display(self, state):
		"Print or otherwise display the state."
		state.printBoard	


 
